package data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SequentialData
{
    private ArrayList<double[]> dataPoints;

    private boolean[] allTrue;

    public SequentialData()
    {
        dataPoints = new ArrayList<double[]>();
    }

    SequentialData(ArrayList<double[]> dataPoints)
    {
        this.dataPoints = dataPoints;
    }

    public void addDataPoint(double[] point)
    {
        dataPoints.add(point);
    }

    public int getDimension()
    {
        return dataPoints.get(0).length;
    }

    public ArrayList<double[]> getdataPoints()
    {
        return dataPoints;
    }


    public SequentialData getMergedData(int numPoints, double percentOverlap)
    {
        if (allTrue == null)
        {
            allTrue = new boolean[getDimension()];
            Arrays.fill(allTrue, true);
        }
        return getMergedData(numPoints, allTrue, percentOverlap);
    }


    /**
     * creates a reduced size SequetialData which merges dataPoints
     * by computing the average of a series of partially overlapping subsets
     * of the initial dataPoint set. includedDimensions is an array of length matching the
     * point dimension and determines which dimensions should be included
     *
     * @param numPoints          desired number of dataPoints
     * @param includedDimensions one can decide to exclude certain dimensions from the data.
     * @param percentOverlap     percentage of overlap for merged Sections
     * @return merged and filtered data
     */
    public SequentialData getMergedData(int numPoints, boolean[] includedDimensions, double percentOverlap)
    {
        int mindiv = dataPoints.size() / numPoints;

        int overlap = (int) Math.ceil(percentOverlap * mindiv);

        ArrayList<double[]> mergedData = new ArrayList<double[]>(numPoints);

        for (int i = 0; i < numPoints; i++)
        {
            int start = Math.max(0, i * mindiv - overlap);
            int end = Math.min(dataPoints.size(), (i + 1) * mindiv + overlap);
            mergedData.add(getAverage(dataPoints.subList(start, end), includedDimensions));
        }

        return new SequentialData(mergedData);

    }


    public double[] flatData()
    {

        double[] data = new double[getDimension() * dataPoints.size()];

        int j = 0;
        for (double[] dataPoint : dataPoints)
        {
            for (int i = 0; i < dataPoint.length; i++)
            {
                data[j++] = dataPoint[i];
            }

        }

        return data;
    }


    private double[] getAverage(List<double[]> dataPoints, boolean[] activeFeatures)
    {
        int startDimension = getDimension();
        int numPoints = dataPoints.size();

        int finalDimension = 0;
        int d = 0;
        while (d < activeFeatures.length)
            finalDimension += activeFeatures[d++] ? 1 : 0;

        double[] s = new double[finalDimension];
        for (double[] seg : dataPoints)
        {
            int k = 0;
            for (int i = 0; i < startDimension; i++)
            {
                if (activeFeatures[i])
                {
                    s[k++] += seg[i];
                }
            }
        }

        for (int i = 0; i < finalDimension; i++)
        {
            s[i] /= numPoints;
        }

        return s;
    }
}
